package com.hbnrtech.sip.gb28181.handler.service;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import com.hbnrtech.sip.gb28181.SipLayer;
import com.hbnrtech.sip.gb28181.config.SipConfigProperties;
import com.hbnrtech.sip.gb28181.deivce.DeviceRegistry;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.sip.ClientTransaction;
import javax.sip.InvalidArgumentException;
import javax.sip.SipException;
import javax.sip.SipProvider;
import javax.sip.address.Address;
import javax.sip.address.AddressFactory;
import javax.sip.address.SipURI;
import javax.sip.header.*;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicLong;

@Service
@Slf4j
public class SipQueryService {

    @Autowired
    private  SipConfigProperties sipConfigProperties;

    @Autowired
    @Lazy
    private SipLayer sipLayer;

    @Autowired
    private  HeaderFactory headerFactory;
    @Autowired
    private  AddressFactory addressFactory;
    @Autowired
    private  MessageFactory messageFactory;
    @Autowired
    private  DeviceRegistry deviceRegistry; // 可能需要获取设备信息

    // 用于生成递增的 CSeq (简单实现，生产环境可能需要更完善的序列管理器)
    private final AtomicLong cseqCounter = new AtomicLong(1);

    // 用于生成 SN (Sequence Number)
    // 实际应用中，SN 需要与回调或 Future 关联，以便匹配响应
    private final AtomicLong snCounter = new AtomicLong(RandomUtil.randomInt(1000, 10000));

    /**
     * 向设备发送 Catalog (目录查询) 请求
     */
    public void queryCatalog(DeviceRegistry.DeviceInfo deviceInfo)
            throws SipException, ParseException, InvalidArgumentException {

        String deviceId = deviceInfo.getDeviceId();
        String transport = deviceInfo.getTransport();
        SipProvider sipProvider = sipLayer.getSipProvider(transport);
        log.info("Sending Catalog query to device: {}", deviceId);

        // 构建目标 Request URI (目标是设备的地址)
        SipURI requestUri = addressFactory.createSipURI(deviceId, deviceInfo.getIp() + ":" + deviceInfo.getPort());
        requestUri.setTransportParam(transport);

        // 构建 From Header
        SipURI fromUri = addressFactory.createSipURI(sipConfigProperties.getDomain(), sipConfigProperties.getIp());
        fromUri.setPort(sipConfigProperties.getPort());
        Address fromAddress = addressFactory.createAddress(fromUri);
        String fromTag = UUID.fastUUID().toString(); // MESSAGE 请求也需要 From Tag
        FromHeader fromHeader = headerFactory.createFromHeader(fromAddress, fromTag);

        // 构建 To Header
        SipURI toUri = addressFactory.createSipURI(deviceId, sipConfigProperties.getDomain()); // To 的域是平台域
        Address toAddress = addressFactory.createAddress(toUri);
        ToHeader toHeader = headerFactory.createToHeader(toAddress, null); // To Tag 由响应设置

        // 构建 Via Header Via 指示响应回来的地址，必须是公网可达的
        ArrayList<ViaHeader> viaHeaders = new ArrayList<>();
        ViaHeader viaHeader = headerFactory.createViaHeader(
                sipConfigProperties.getPublicIp(),
                sipConfigProperties.getPublicPort(),
                transport,
                null);
        // 添加 rport 参数，让设备探测并返回实际源端口 (有助于穿透某些 NAT)
        viaHeader.setRPort();
        viaHeaders.add(viaHeader);

        // 构建 Call-ID, CSeq, Max-Forwards
        CallIdHeader callIdHeader = sipProvider.getNewCallId(); // 使用 Provider 生成新的 Call-ID
        CSeqHeader cSeqHeader = headerFactory.createCSeqHeader(cseqCounter.getAndIncrement(), Request.MESSAGE); // 递增 CSeq, 方法 MESSAGE
        MaxForwardsHeader maxForwards = headerFactory.createMaxForwardsHeader(70);

        // 创建 MESSAGE 请求
        Request messageRequest = messageFactory.createRequest(
                requestUri,
                Request.MESSAGE,
                callIdHeader,
                cSeqHeader,
                fromHeader,
                toHeader,
                viaHeaders,
                maxForwards
        );

        // 添加 Contact Header
        SipURI contactUri = addressFactory.createSipURI(null, sipConfigProperties.getPublicIp());
        contactUri.setPort(sipConfigProperties.getPublicPort());
        contactUri.setTransportParam(transport);
        Address contactAddress = addressFactory.createAddress(contactUri);
        ContactHeader contactHeader = headerFactory.createContactHeader(contactAddress);
        messageRequest.setHeader(contactHeader);

        // 构建 XML 内容
        long currentSn = snCounter.getAndIncrement(); // 获取并递增 SN
        String catalogXml = buildCatalogQueryXml(deviceId, currentSn);
        log.debug("Catalog Query XML for SN {}:\n{}", currentSn, catalogXml);

        // 设置 Content-Type 和 Content
        // GB28181 规定 Content-Type 为 Application/MANSCDP+xml
        ContentTypeHeader contentTypeHeader = headerFactory.createContentTypeHeader("Application", "MANSCDP+xml");
        // 编码默认为 GB2312，如果你的设备或平台使用 UTF-8，请修改
        Charset charset = Charset.forName("GB2312");
        try {
            messageRequest.setContent(catalogXml.getBytes(charset), contentTypeHeader);
        } catch (ParseException e) {
            log.error("Error setting message content", e);
            throw e; // 重新抛出
        }

        // 创建客户端事务并发送
        ClientTransaction clientTransaction = sipProvider.getNewClientTransaction(messageRequest);

        // !!! 重要：需要存储 SN 与事务/回调/Future 的关联关系，以便处理响应 !!!
        // 例如: queryContextManager.addQueryContext(currentSn, clientTransaction, someCallbackOrFuture);
        log.info("Storing context for Catalog query SN: {}", currentSn);

        // 发送请求
        clientTransaction.sendRequest();

        log.info("Catalog query (SN: {}) sent successfully to device {}.", currentSn, deviceId);

    }

    /**
     * 构建 Catalog 查询的 XML 字符串
     */
    private String buildCatalogQueryXml(String targetDeviceId, long sn) {
        // 或 UTF-8
        return "<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n" + // 或 UTF-8
                "<Query>\r\n" +
                "<CmdType>Catalog</CmdType>\r\n" +
                "<SN>" + sn + "</SN>\r\n" +
                "<DeviceID>" + targetDeviceId + "</DeviceID>\r\n" +
                "</Query>\r\n";
    }
}
